home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************************/
- /* */
- /* HappyFracs */
- /* ---------- */
- /* */
- /* © DayStar Digital, Inc. 1995-1996 */
- /* All Rights Reserved. */
- /* */
- /************************************************************************************/
-
- #include <MP.h>
-
- /*----------------------------------------------------------------------------------*/
- #define kTMCreate 1
- #define kTMRun 2
- #define kTMQuit 3
- #define kTMReady 4
-
- /*----------------------------------------------------------------------------------*/
- typedef OSErr (*MPWorkFunction)( void *params );
-
- typedef struct {
- MPTaskID taskID;
- MPQueueID appToTask;
- MPQueueID taskToApp;
- MPWorkFunction workFunction;
- void *params;
- } sTaskData, *sTaskDataPtr;
-
- /*----------------------------------------------------------------------------------*/
- OSErr fMPInitialize( long *numProcessors );
- OSErr fMPTasksCreate( long numTasks );
- void fMPTaskRun( long whichTask, MPWorkFunction workFunction, void *params );
- void fMPTaskWait( long whichTask );
- void fMPTasksQuit( long numTasks );
- static OSStatus fTask( void *theParameter );
-
- /*----------------------------------------------------------------------------------*/
- sTaskDataPtr gTaskData; /* Task information slots */
-
- /*==================================================================================*/
- OSErr fMPInitialize( long *numProcessors ) {
- /* This function is called when PowerFrax starts up. It makes sure the */
- /* multiprocessing library is loaded and tells PowerFrax how many processors are */
- /* available. */
-
- OSErr theErr;
-
- theErr = noErr;
-
- /* Check that the MP library is present */
- if( theErr == noErr )
- if( !MPLibraryIsLoaded() )
- theErr = 1;
-
- /* Get the processor count */
- if( theErr == noErr )
- *numProcessors = MPProcessors();
-
- return( theErr );
- }
-
- /*==================================================================================*/
- OSErr fMPTasksCreate( long numTasks ) {
- /* PowerFrax calls this function soon after startup and everytime the user selects */
- /* a different number of processors to use from the Multiprocessing menu. */
- /* It creates one communication 'slot' for each task, it creates the queues used to */
- /* communicate with the task, and creates the task itself passing the address of */
- /* the 'slot' to the task as its sole parameter. */
- /* Each task is asked to acknowledge creation. */
-
- long i;
- OSErr theErr;
- long message;
-
- theErr = noErr;
-
- /* Create an array of sTaskDataPtr (defined above) with one 'slot' for each */
- /* task to be created. */
- gTaskData = NULL;
- if( theErr == noErr ) {
- gTaskData = (sTaskDataPtr)NewPtrClear( numTasks * sizeof( sTaskData ) );
- if( gTaskData == NULL )
- theErr = MemError();
- }
-
- /* Create one task per processor */
- for( i = 0; i < numTasks && theErr == noErr; i++ ) {
- /* Create the message queues by which to communicate the action */
- /* messages the app. sends to the tasks, and by which to receive the */
- /* status message returned by the tasks. */
- if( theErr == noErr )
- theErr = MPCreateQueue( &gTaskData[i].appToTask );
- if( theErr == noErr )
- theErr = MPCreateQueue( &gTaskData[i].taskToApp );
- if( theErr == noErr )
- theErr = MPCreateTask( fTask, &gTaskData[i], 2048, NULL, NULL, NULL, 0, &gTaskData[i].taskID );
- if( theErr == noErr ) {
- MPNotifyQueue( gTaskData[i].appToTask, (void *)kTMCreate, NULL, NULL );
- MPWaitOnQueue( gTaskData[i].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
- }
- }
-
- return( theErr );
- }
-
- /*==================================================================================*/
- void fMPTaskRun( long whichTask, MPWorkFunction workFunction, void *params ) {
- /* Prepare data for the specified task and set it running. Normally each parameter */
- /* passed to this type of function would be copied into the gTaskData block for the */
- /* specified task. However, since PowerFrax provides MP services to any fractal */
- /* generator that requests it, the parameters are instead passed as an arbitrary */
- /* block of data. Since the parameters are different for each request PowerFrax */
- /* maintains one unique block to use for each available task. */
-
- gTaskData[whichTask].workFunction = workFunction;
- gTaskData[whichTask].params = params;
-
- MPNotifyQueue( gTaskData[whichTask].appToTask, (void *)kTMRun, NULL, NULL );
- }
-
- /*==================================================================================*/
- void fMPTaskWait( long whichTask ) {
- /* Wait until the specified task is finished doing work. PowerFrax operates by */
- /* starting one scanline per task and then waiting for all of the tasks to finish. */
- /* If continues to do this until the image is finished or more than a tenth of a */
- /* second has elapsed. The process is repeated if necessary every time a NULL event */
- /* is received in the WaitNextEvent() loop. */
-
- long message;
-
- MPWaitOnQueue( gTaskData[whichTask].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
- }
-
- /*==================================================================================*/
- void fMPTasksQuit( long numTasks ) {
- /* PowerFrax calls this function before quitting and everytime the user selects a */
- /* different number of processors to use from the Multiprocessing menu. */
- /* The tasks are notified that they are about to be terminated. Once they */
- /* acknowledge, they are terminated and all the resources they were using are */
- /* deallocated. */
-
- long i;
- long message;
-
- if( gTaskData != NULL ) {
- for( i = 0; i < numTasks; i++ ) {
- /* If this task was successfully created then try to close it down */
- /* properly. */
- if( gTaskData[i].appToTask != NULL &&
- gTaskData[i].taskToApp != NULL &&
- gTaskData[i].taskID != NULL ) {
- MPNotifyQueue( gTaskData[i].appToTask, (void *)kTMQuit, NULL, NULL );
- MPWaitOnQueue( gTaskData[i].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
- }
- /* Delete the task resources */
- if( gTaskData[i].taskID != NULL )
- MPTerminateTask( gTaskData[i].taskID, noErr );
- if( gTaskData[i].taskToApp != NULL )
- MPDeleteQueue( gTaskData[i].taskToApp );
- if( gTaskData[i].appToTask != NULL )
- MPDeleteQueue( gTaskData[i].appToTask );
- }
- DisposePtr( (Ptr)gTaskData );
- }
- }
-
- /*==================================================================================*/
- /*==================================================================================*/
- static OSStatus fTask( void *theParameter ) {
- /* This is the actual task. The parameter was provided at task creation time and in */
- /* this case is a pointer to a 'slot' containing the information for use by this */
- /* task. Note that the function that performs the actual work and the parameters to */
- /* use are variables that are established in fMPTaskRun(). This lets PowerFrax */
- /* provide MP services to any fractal generator willing to provide such a function. */
-
- Boolean finished;
- sTaskDataPtr p;
- long message;
-
- /* The following statement is executed once, immediately after task creation */
- p = (sTaskDataPtr)theParameter;
-
- finished = false;
- while( !finished ) {
- MPWaitOnQueue( p->appToTask, (void **)&message, NULL, NULL, kDurationForever );
- switch( message ) {
- case kTMCreate:
- break;
- case kTMRun:
- p->workFunction( p->params );
- break;
- case kTMQuit:
- finished = true;
- break;
- }
- MPNotifyQueue( p->taskToApp, (void *)kTMReady, NULL, NULL );
- }
-
- return( noErr );
- }
-
- /*==================================================================================*/
- /*==================================================================================*/
-